﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Web.Mvc;

namespace Drill.Web.Mvc.Tests.TestHelpers
{
	public class MockDependencyResolver : IDependencyResolver
	{
		private readonly Dictionary<string, Func<object>> _getInstanceHandlerMap;

		public MockDependencyResolver()
		{
			_getInstanceHandlerMap = new Dictionary<string, Func<object>>
				{
					{ CreateHanlderKey(typeof(IController), "MyFirstTest"), HandleGetInstanceMyFirstTestController }
				  , { CreateHanlderKey(typeof(IController), "MyLastTest"), HandleGetInstanceMyLastTestController }
				};
		}

		private static object HandleGetInstanceMyFirstTestController()
		{
			return new MyFirstTestController();
		}

		private static object HandleGetInstanceMyLastTestController()
		{
			throw new Exception("This is used to test what happens when an exception is thrown while attempting to resolve an instance.");
		}

		private static string CreateHanlderKey(Type type, string name)
		{
			return type.FullName + "!" + name;
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		/// <filterpriority>2</filterpriority>
		public void Dispose()
		{
		}

		/// <summary>
		/// Gets an instance of the type specified by <paramref name="targetType"/>.
		/// </summary>
		/// <param name="targetType">The type of object to be retrieved.</param>
		/// <returns>An instance of the requested type.</returns>
		public virtual object GetInstance(Type targetType)
		{
			Func<object> handler;
			string key = CreateHanlderKey(targetType, string.Empty);
			return _getInstanceHandlerMap.TryGetValue(key, out handler) ? handler() : null;
		}

		/// <summary>
		/// Gets a named instance of the type specified by <paramref name="targetType"/>.
		/// </summary>
		/// <param name="targetType">The type of object to be retrieved.</param>
		/// <param name="name">The name of the specific object instance.</param>
		/// <returns>An instance of the requested named type.</returns>
		public virtual object GetInstance(Type targetType, string name)
		{
			Func<object> handler;
			string key = CreateHanlderKey(targetType, name);
			return _getInstanceHandlerMap.TryGetValue(key, out handler) ? handler() : null;
		}

		/// <summary>
		/// Get all instances of the type specified by <paramref name="targetType"/>.
		/// </summary>
		/// <param name="targetType">The type of object to be retrieved.</param>
		/// <returns>
		/// An <see cref="IEnumerable"/> instance representing all 
		/// available instances of the requested type.
		/// </returns>
		public virtual IEnumerable GetAllInstances(Type targetType)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// Gets an instance of the type specified by <typeparamref name="TTargetType"/>.
		/// </summary>
		/// <typeparam name="TTargetType">The type of object to be retrieved.</typeparam>
		/// <returns>An instance of the requested type.</returns>
		public virtual TTargetType GetInstance<TTargetType>()
		{
			Func<object> handler;
			string key = CreateHanlderKey(typeof(TTargetType), string.Empty);
			return _getInstanceHandlerMap.TryGetValue(key, out handler) ? (TTargetType)handler() : default(TTargetType);
		}

		/// <summary>
		/// Gets a named instance of the type specified by <typeparamref name="TTargetType"/>.
		/// </summary>
		/// <typeparam name="TTargetType">The type of object to be retrieved.</typeparam>
		/// <param name="name">Name the object was registered with.</param>
		/// <returns>An instance of the requested named type.</returns>
		public virtual TTargetType GetInstance<TTargetType>(string name)
		{
			Func<object> handler;
			string key = CreateHanlderKey(typeof(TTargetType), name);
			return _getInstanceHandlerMap.TryGetValue(key, out handler) ? (TTargetType)handler() : default(TTargetType);
		}

		/// <summary>
		/// Get all instances of the type specified by <typeparamref name="TTargetType"/>.
		/// </summary>
		/// <typeparam name="TTargetType">The type of object to be retrieved.</typeparam>
		/// <returns>
		/// An <see cref="IEnumerable{TTargetType}"/> instance representing all 
		/// available instances of the requested type.
		/// </returns>
		public virtual IEnumerable<TTargetType> GetAllInstances<TTargetType>()
		{
			throw new NotImplementedException();
		}
	}
}